Search K
Appearance
Appearance
容器是隔离环境,容器内程序的文件、配置、运行时产生的容器都在容器内部,我们要读写容器内的文件非常不方便。大家思考几个问题:
因此,容器提供程序的运行环境,但是程序运行产生的数据、程序运行依赖的配置都应该与容器解耦。
数据卷(volume) 是一个虚拟目录,是 容器内目录 与 宿主机目录 之间映射的桥梁。
官方解释
Volumes are the preferred mechanism for persisting data generated by and used by Docker containers. While bind mounts are dependent on the directory structure and OS of the host machine, volumes are completely managed by Docker. Volumes have several advantages over bind mounts: 卷是 Docker 容器生成和使用数据的首选持久化机制。绑定挂载依赖于主机的目录结构和操作系统,而卷则完全由 Docker 管理。与绑定挂载相比,卷有几个优点:
In addition, volumes are often a better choice than persisting data in a container's writable layer, because a volume doesn't increase the size of the containers using it, and the volume's contents exist outside the lifecycle of a given container. 此外,与在容器的可写层中持久化数据相比,卷通常是更好的选择,因为卷不会增加使用它的容器的大小,而且卷的内容存在于给定容器的生命周期之外。
以 Nginx 为例,我们知道 Nginx 中有两个关键的目录:
html:放置一些静态资源conf:放置配置文件如果我们要让 Nginx 代理我们的静态资源,最好是放到 html 目录;如果我们要修改 Nginx 的配置,最好是找到 conf 下的 nginx.conf 文件。
但遗憾的是,容器运行的 Nginx 所有的文件都在容器内部。所以我们必须利用数据卷将两个目录与宿主机目录关联,方便我们操作。

在上图中:
conf、htmlconf 目录和 html 目录分别与两个数据卷关联。/var/lib/docker/volumes/conf/_data 目录和 /var/lib/docker/volumes/html/_data 目录这样以来,容器内的 conf 和 html 目录就 与宿主机的 conf 和 html 目录关联起来,我们称为挂载。此时,我们操作宿主机的 /var/lib/docker/volumes/html/_data 就是在操作容器内的 /usr/share/nginx/html/_data 目录。只要我们将静态资源放入宿主机对应目录,就可以被 Nginx 代理了。
TIP
/var/lib/docker/volumes 这个目录就是默认的存放所有容器数据卷的目录,其下再根据数据卷名称创建新目录,格式为 /数据卷名/_data。❯ docker volume --help
Usage: docker volume COMMAND
Manage volumes
Commands:
create Create a volume
inspect Display detailed information on one or more volumes
ls List volumes
prune Remove unused local volumes
rm Remove one or more volumes
Run 'docker volume COMMAND --help' for more information on a command.❯ tldr docker volume
Manage Docker volumes.
More information: <https://docs.docker.com/engine/reference/commandline/volume/>.
Create a volume:
docker volume create volume_name
Create a volume with a specific label:
docker volume create --label label volume_name
Create a `tmpfs` volume a size of 100 MiB and an uid of 1000:
docker volume create --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 volume_name
List all volumes:
docker volume ls
Remove a volume:
docker volume rm volume_name
Display information about a volume:
docker volume inspect volume_name
Remove all unused local volumes:
docker volume prune
Display help for a subcommand:
docker volume subcommand --help| 命令 | 说明 | 文档地址 |
|---|---|---|
docker volume create | 创建数据卷 | docker volume create |
docker volume ls | 查看所有数据卷 | docker volume ls |
docker volume rm | 删除指定数据卷 | docker volume rm |
docker volume inspect | 查看某个数据卷的详情 | docker volume inspect |
docker volume prune | 清除数据卷 | docker volume prune |
注意
容器与数据卷的挂载要在创建容器时配置,对于创建好的容器,是不能设置数据卷的。而且创建容器的过程中,数据卷会自动创建。
演示一下利用 Nginx 容器部署静态资源:nginx 的 html 命名数据卷。
需求
html 目录下的 index.html 文件内容html 目录提示
docker run 命令时,使用 -v 数据卷:容器内目录 可以完成数据卷挂载首先创建容器并指定数据卷,注意通过 -v 参数来指定数据卷。
❯ docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
578acb154839: Pull complete
e398db710407: Pull complete
85c41ebe6d66: Pull complete
7170a263b582: Pull complete
8f28d06e2e2e: Pull complete
6f837de2f887: Pull complete
c1dfc7e1671e: Pull complete
Digest: sha256:86e53c4c16a6a276b204b0fd3a8143d86547c967dc8258b3d47c3a21bb68d3c6
Status: Downloaded newer image for nginx:latest
a415c4c37209f030752326a41ddc5485ed83b498087e6082f0121de3a3bbbb52查看数据卷。
❯ docker volume ls
DRIVER VOLUME NAME
local 0cdc74b1d00927c0e628ca8d6600316fc1c4c90b15eec972b75a8ac008661819
local html查看数据卷详情。
❯ docker volume inspect html
[
{
"CreatedAt": "2023-11-05T09:32:30+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/html/_data",
"Name": "html",
"Options": null,
"Scope": "local"
}
]查看 /var/lib/docker/volumes/html/_data 目录。
❯ la
.rw-r--r-- ubuntu ubuntu 497B 2 weeks ago 50x.html
.rw-r--r-- ubuntu ubuntu 19B an hour ago index.html进入该目录,并随意修改 index.html 内容。
❯ curl http://150.158.99.53:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
❯ vim index.html打开页面查看效果。
❯ cat -n index.html
1 Welcome to Docker!
❯ curl http://150.158.99.53:80
Welcome to Docker!进入容器内部,查看 /usr/share/nginx/html 目录内的文件是否变化。
❯ dex nginx cat /usr/share/nginx/html/index.html # dex is alias of 'docker exec -it'
Welcome to Docker!演示一下 MySQL 的匿名数据卷。
查看 MySQL 容器详细信息。
❯ dkin mysql # dkin is alias of 'docker inspect'
... 输出内容太多,省略
❯ dkin mysql | jq '.[0].Config.Volumes' # 使用 jq 查看容器配置的数据卷
{
"/var/lib/mysql": {}
}
❯ dkin mysql | jq '.[0].Mounts' # 使用 jq 查看容器挂载的数据卷
[
{
"Type": "volume",
"Name": "9c23b8c7e4d34c0458f255c74c577a57cc97697f9b29619324458cbd9bd417d6",
"Source": "/var/lib/docker/volumes/9c23b8c7e4d34c0458f255c74c577a57cc97697f9b29619324458cbd9bd417d6/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
]使用 jq 查看容器配置的数据卷。dkin mysql | jq '.[0].Config.Volumes
{
"/var/lib/mysql": {}
}可以发现这个容器声明了一个本地目录,需要挂载数据卷,但是数据卷未定义。这就是匿名卷。
使用 jq 查看容器挂载的数据卷。dkin mysql | jq '.[0].Mounts'
[
{
"Type": "volume",
"Name": "9c23b8c7e4d34c0458f255c74c577a57cc97697f9b29619324458cbd9bd417d6",
"Source": "/var/lib/docker/volumes/9c23b8c7e4d34c0458f255c74c577a57cc97697f9b29619324458cbd9bd417d6/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
]可以发现,其中有几个关键属性:
上述配置是将容器内的 /var/lib/mysql 这个目录,与数据卷 9c23b8c7e4d34c0458f255c74c577a57cc97697f9b29619324458cbd9bd417d6 挂载。于是在宿主机中就有了 /var/lib/docker/volumes/9c23b8c7e4d34c0458f255c74c577a57cc97697f9b29619324458cbd9bd417d6/_data 这个目录。这就是匿名数据卷对应的目录,其使用方式与普通数据卷没有差别。
查看该目录下的 MySQL 的 data 文件。
❯ lsa /var/lib/docker/volumes/9c23b8c7e4d34c0458f255c74c577a57cc97697f9b29619324458cbd9bd417d6/_data
total 99M
drwxrwxrwt 7 lxd ubuntu 4.0K Nov 5 11:00 .
drwx-----x 3 root root 4.0K Nov 5 10:59 ..
-rw-r----- 1 lxd docker 56 Nov 5 10:59 auto.cnf
-rw-r----- 1 lxd docker 2.9M Nov 5 11:00 binlog.000001
-rw-r----- 1 lxd docker 157 Nov 5 11:00 binlog.000002
-rw-r----- 1 lxd docker 32 Nov 5 11:00 binlog.index
-rw------- 1 lxd docker 1.7K Nov 5 11:00 ca-key.pem
-rw-r--r-- 1 lxd docker 1.1K Nov 5 11:00 ca.pem
-rw-r--r-- 1 lxd docker 1.1K Nov 5 11:00 client-cert.pem
-rw------- 1 lxd docker 1.7K Nov 5 11:00 client-key.pem
-rw-r----- 1 lxd docker 192K Nov 5 11:02 '#ib_16384_0.dblwr'
-rw-r----- 1 lxd docker 8.2M Nov 5 10:59 '#ib_16384_1.dblwr'
-rw-r----- 1 lxd docker 5.6K Nov 5 11:00 ib_buffer_pool
-rw-r----- 1 lxd docker 12M Nov 5 11:00 ibdata1
-rw-r----- 1 lxd docker 12M Nov 5 11:00 ibtmp1
drwxr-x--- 2 lxd docker 4.0K Nov 5 11:00 '#innodb_redo'
drwxr-x--- 2 lxd docker 4.0K Nov 5 11:00 '#innodb_temp'
drwxr-x--- 2 lxd docker 4.0K Nov 5 11:00 mysql
-rw-r----- 1 lxd docker 31M Nov 5 11:00 mysql.ibd
lrwxrwxrwx 1 lxd docker 27 Nov 5 11:00 mysql.sock -> /var/run/mysqld/mysqld.sock
drwxr-x--- 2 lxd docker 4.0K Nov 5 11:00 performance_schema
-rw------- 1 lxd docker 1.7K Nov 5 11:00 private_key.pem
-rw-r--r-- 1 lxd docker 452 Nov 5 11:00 public_key.pem
-rw-r--r-- 1 lxd docker 1.1K Nov 5 11:00 server-cert.pem
-rw------- 1 lxd docker 1.7K Nov 5 11:00 server-key.pem
drwxr-x--- 2 lxd docker 4.0K Nov 5 11:00 sys
-rw-r----- 1 lxd docker 16M Nov 5 11:02 undo_001
-rw-r----- 1 lxd docker 16M Nov 5 11:02 undo_002注意
每一个不同的镜像,将来创建容器后内部有哪些目录可以挂载,可以参考 DockerHub 对应镜像的页面。
总结
-v 数据卷名:容器内目录 完成挂载docker volume ls: 查看数据卷docker volume rm: 删除数据卷docker volume inspect: 查看数据卷详情docker volume prune: 删除未使用的数据卷